package cn.tedu.csmall.product.service.impl;

import cn.tedu.csmall.commons.pojo.vo.PageData;
import cn.tedu.csmall.commons.util.PageInfoToPageDataConverter;
import cn.tedu.csmall.product.ex.ServiceException;
import cn.tedu.csmall.product.mapper.BrandCategoryMapper;
import cn.tedu.csmall.product.mapper.CategoryAttributeTemplateMapper;
import cn.tedu.csmall.product.mapper.CategoryMapper;
import cn.tedu.csmall.product.mapper.SPUMapper;
import cn.tedu.csmall.product.pojo.entity.*;
import cn.tedu.csmall.product.pojo.param.CategoryAddNewParam;
import cn.tedu.csmall.product.pojo.param.CategoryUpdateInfoParam;
import cn.tedu.csmall.product.pojo.vo.*;
import cn.tedu.csmall.product.service.CategoryService;
import cn.tedu.csmall.product.web.JsonResult;
import cn.tedu.csmall.product.web.ServiceCode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Service
@Slf4j
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private CategoryAttributeTemplateMapper categoryAttributeTemplateMapper;
    @Autowired
    private BrandCategoryMapper brandCategoryMapper;
    @Autowired
    private SPUMapper spuMapper;

    @Override
    public void addNew(CategoryAddNewParam categoryAddNewParam) {

        // 新增前查询名称是否被占用，若占用，则不允许插入
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", categoryAddNewParam.getName());
        int count = categoryMapper.selectCount(queryWrapper);
        if (count > 0) {
            String message = "【ServiceException:添加类别失败，类别名称已经被占用！】";
            log.debug("【log.info:添加类别失败，类别名称已经被占用！】");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 判断新增数据的父级ID是否为0
        //      为0：则自己就是最高级，设置depth为1
        //      不为0：自己不是最高级，查询其父级是否存在
        //          不存在：禁止插入
        //          存在：设置depth为父级的depth + 1
        long parentId = categoryAddNewParam.getParentId();
        int depth = 1;
        CategoryStandardVO parentCategory = null;
        if (parentId != 0) {
            parentCategory = categoryMapper.getStandardById(parentId);
            if (parentCategory == null) {
                String message = "添加类别失败，父级类别不存在！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
            } else {
                depth = parentCategory.getDepth() + 1;
            }
        }

        // 新增数据的父级ID为0
        Category category = new Category();
        BeanUtils.copyProperties(categoryAddNewParam,category);
        category.setDepth(depth);
        category.setIsParent(0);
        category.setGmtCreate(LocalDateTime.now());
        category.setGmtModified(LocalDateTime.now());

        int rows = categoryMapper.insert(category);
        if (rows != 1) {
            String msg = "添加类别失败，服务器忙，请稍后再试！";
            log.warn(msg);
            // 抛出异常就能回滚
            throw new ServiceException(ServiceCode.ERR_INSERT, msg);
        }

        // 判断新增数据的父级ID是否不为0（代表改数据有父级），并判断其父级类别的isParent是否为0
        if (parentId != 0 && parentCategory.getIsParent() == 0) {
            // 是：将父级类别的isParent更新为1
            Category updateParentCategory = new Category();
            updateParentCategory.setId(parentId);
            updateParentCategory.setIsParent(1);
            rows = categoryMapper.updateById(updateParentCategory);
            if (rows != 1) {
                String message = "添加类别失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }
    }

    @Override
    public void deleteById(Long categoryId) {
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",categoryId);
        CategoryStandardVO currentCategory = categoryMapper.getStandardById(categoryId);

        if (currentCategory == null) {
            String message = "【ServiceException:删除失败，没有该类别ID！】";
            log.debug("【log.info:删除失败，没有该类别ID！！】");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 判断查询结果中的isParent是否为1，如果是，则抛出异常
        if (currentCategory.getIsParent() == 1) {
            String message = "删除类别失败，该类别仍包含子级类别！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 检查是否有属性模板（pms_category_attribute_template）关联到了此类别，如果有，则不能删除该类别
        QueryWrapper<CategoryAttributeTemplate> categoryAttributeTemplateQueryWrapper = new QueryWrapper<>();
        categoryAttributeTemplateQueryWrapper.eq("category_id",categoryId);
        int countByCategoryId1 = categoryAttributeTemplateMapper.selectCount(categoryAttributeTemplateQueryWrapper);
        if (countByCategoryId1 > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "该类别有附属属性模板，请转移后删除！");
        }

        // 检查是否有SPU关联到了此类别，如果有，则不能删除该类别
        QueryWrapper<SPU> spuQueryWrapper = new QueryWrapper<>();
        spuQueryWrapper.eq("category_id",categoryId);
        int countByCategoryId2 = spuMapper.selectCount(spuQueryWrapper);
        if (countByCategoryId2 > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "该类别有附属SPU，请转移后删除！");
        }

        // 检查是否有品牌关联到了此类别，如果有，则不能删除该类别
        QueryWrapper<BrandCategory> skuQueryWrapper = new QueryWrapper<>();
        skuQueryWrapper.eq("category_id",categoryId);
        int countByCategoryId3 = brandCategoryMapper.selectCount(skuQueryWrapper);
        if (countByCategoryId3 > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "该类别有附属品牌，请转移后删除！");
        }

        // 不会抛出异常（即该类别没有附属的东西），则允许删除
        int rows = categoryMapper.deleteById(categoryId);
        if (rows != 1) {
            String msg = "删除类别失败，服务器忙，请稍后再试！";
            log.warn(msg);
            // 抛出异常就能回滚
            throw new ServiceException(ServiceCode.ERR_DELETE, msg);
        }

        // 本次删除的是父级中的最后一个子级，则需要将父级的`is_parent`更新为0
        Long parentId = currentCategory.getParentId();
        int count = categoryMapper.countByParentId(parentId);
        // 判断统计结果为0，则将父级类别的isParent更新为0
        if (count == 0) {
            Category parentCategory = new Category();
            parentCategory.setId(parentId);
            parentCategory.setIsParent(0);
            rows = categoryMapper.updateById(parentCategory);
            if (rows != 1) {
                String message = "删除类别失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }
    }

    @Override
    public void updateInfoById(Long id, CategoryUpdateInfoParam categoryUpdateInfoParam) {
        log.debug("开始处理【修改类别详情】的业务，参数：{}",categoryUpdateInfoParam);

        //修改前查询数据是否存在
        CategoryStandardVO queryResult = categoryMapper.getStandardById(id);
        if (queryResult == null) {
            // 不存在：抛出异常，回滚
            String message = "修改类别详情失败，尝试修改的类别数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        Category category = new Category();
        BeanUtils.copyProperties(categoryUpdateInfoParam,category);
        category.setId(id);
        category.setGmtModified(LocalDateTime.now());
        int rows = categoryMapper.updateById(category);
        if (rows != 1) {
            String msg = "更新类别详情失败，服务器忙，请稍后再试！";
            log.warn(msg);
            // 抛出异常就能回滚
            throw new ServiceException(ServiceCode.ERR_UPDATE, msg);
        }
        log.debug("新的类别数据更新到数据库完成！");
    }

    @Override
    public PageData<CategoryListItemVO> listByParentId(Long parentId, Integer pageNum) {
        int pageSize = 5;
        // 参数少的调用参数多的
        return listByParentId(parentId, pageNum, pageSize);
    }

    @Override
    public PageData<CategoryListItemVO> listByParentId(Long parentId, Integer pageNum, Integer pageSize) {
        log.debug("开始处理【根据父级类别查询子级类别列表】的业务，页码：{}，父级ID：{}", pageNum, parentId);
        PageHelper.startPage(pageNum, pageSize);
        List<CategoryListItemVO> list = categoryMapper.listByParentId(parentId);
        PageInfo<CategoryListItemVO> pageInfo = new PageInfo<>(list);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }

    @Override
    public CategoryStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询类别】的业务，ID值为：{}", id);
        CategoryStandardVO result = categoryMapper.getStandardById(id);
        if (result == null) {
            String message = "【ServiceException:【根据ID查询相册】失败，相册数据不存在！】";
            log.debug("【根据ID查询相册】失败，相册数据不存在！");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return result;
    }

    @Override
    public void setEnable(Long id, Integer enable) {

        // 修改前判断数据是否存在
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",id);
        int countById = categoryMapper.selectCount(queryWrapper);
        if (countById == 0) {
            String message = "修改启用或者禁用失败，没有该类别！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        Category category = new Category()
                .setId(id)
                .setEnable(enable)
                .setGmtModified(LocalDateTime.now());
        int rows = categoryMapper.updateById(category);
        if (rows != 1) {
            String msg = "设置启用或者禁用失败，服务器忙，请稍后再试！";
            log.warn(msg);
            // 抛出异常就能回滚
            throw new ServiceException(ServiceCode.ERR_UPDATE, msg);
        }
        log.debug("设置类别的启用或者禁用到数据库完成！");
    }

    @Override
    public void setIsDisplay(Long id, Integer isDisplay) {
        // 修改前判断数据是否存在
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",id);
        int countById = categoryMapper.selectCount(queryWrapper);
        if (countById == 0) {
            String message = "修改展示或者不展示失败，没有该类别！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        Category category = new Category()
                .setId(id)
                .setIsDisplay(isDisplay)
                .setGmtModified(LocalDateTime.now());
        int rows = categoryMapper.updateById(category);
        if (rows != 1) {
            String msg = "设置展示或者不展示失败，服务器忙，请稍后再试！";
            log.warn(msg);
            // 抛出异常就能回滚
            throw new ServiceException(ServiceCode.ERR_UPDATE, msg);
        }
        log.debug("设置类别的展示或者不展示到数据库完成！");
    }

    /**
     * 整体流程：
     * 1、遍历所有类别项，找出一级类别
     * 2、转换这些一级类别为类别树，设置 value 和 label ，children 待定；并存入类别树集合
     * 3、调用fillChildren()，如果该一级类别还是父级，再遍历 map 获取当前每个类别，如果遍历的得到的当前类别的父级ID == 一级类别的ID，
     *    则将当前类别转换成类别树，并将之前类别树的children置为当前类别树
     * 4、如果当前类别还是父级，则递归调用fillChildren()
     *
     * @return List<CategoryTreeItemVO>（类别树的集合）（每个一级类别为一项，里面套二级，三级类别）
     */
    @Override
    public List<CategoryTreeItemVO> listTree() {
        // 准备类别树集合
        List<CategoryTreeItemVO> categoryTree = new ArrayList<>();
        // 查询全部类别项
        List<CategoryListItemVO> categoryList = categoryMapper.list();
        // 将类别项转化成以 类别项id 为 key 的 map
        Map<Long, CategoryListItemVO> allCategoryMap = transformListToMap(categoryList);
        // 通过 key 遍历 map
        for (Long key : allCategoryMap.keySet()) {
            // 通过 key 取出每一项为一个类别项
            CategoryListItemVO mapItem = allCategoryMap.get(key);
            // 该类别项为一级类别
            if (mapItem.getParentId() == 0) {
                // 根据类别项中的 id 和 name 填充类别树中 value 和 label
                CategoryTreeItemVO categoryTreeItemVO = convertListItemToTreeItem(mapItem);
                // 类别树集合中添加元素
                categoryTree.add(categoryTreeItemVO);
                // 根据  填充children
                fillChildren(mapItem, categoryTreeItemVO, allCategoryMap);
            }
        }
        return categoryTree;
    }

    // 通过<类别的id, 类别项>作为<key, value>将 categoryList 转化成 Map<Long, CategoryListItemVO>
    private Map<Long, CategoryListItemVO> transformListToMap(List<CategoryListItemVO> categoryList) {
        Map<Long, CategoryListItemVO> categoryMap = new LinkedHashMap<>();
        for (CategoryListItemVO categoryListItemVO : categoryList) {
            if (categoryListItemVO.getEnable() == 0) {
                continue;
            }
            categoryMap.put(categoryListItemVO.getId(), categoryListItemVO);
        }
        return categoryMap;
    }

    // 通过类别列表项的 id 和 name 设置 类别树的 value 和 label
    private CategoryTreeItemVO convertListItemToTreeItem(CategoryListItemVO listItem) {
        return new CategoryTreeItemVO()
                .setValue(listItem.getId())
                .setLabel(listItem.getName());
    }

    // 递归的填充类别树里面 children 的值；传参：（转换成类别树的类别项， 当前类别树(填充了value和label)， 以id为key的类别map）
    private void fillChildren(CategoryListItemVO listItem, CategoryTreeItemVO currentTreeItem, Map<Long, CategoryListItemVO> allCategoryMap) {
        // 有children
        if (listItem.getIsParent() == 1) {
            // 将当前类别树的children初始化，防止空指针异常
            currentTreeItem.setChildren(new ArrayList<>());
            // 取出 map 中的 key 作为一个集合
            Set<Long> keySet = allCategoryMap.keySet();
            // 遍历集合
            for (Long key : keySet) {
                // 取出map中的value（也就是每一个类别项）
                CategoryListItemVO mapItem = allCategoryMap.get(key);
                // 如果遍历的map里的某一项的父级ID == 刚转换成类别树的类别项 的ID（即 map 里面的这一项是它的 children）
                if (mapItem.getParentId() == listItem.getId()) {
                    // 将map里的这一项转换成类别树作为当前类别树的children
                    CategoryTreeItemVO categoryTreeSubItemVO = convertListItemToTreeItem(mapItem);
                    currentTreeItem.getChildren().add(categoryTreeSubItemVO);
                    // 如果遍历的map里的某一项还是父级，递归进行填充children操作
                    if (mapItem.getIsParent() == 1) {
                        fillChildren(mapItem, categoryTreeSubItemVO, allCategoryMap);
                    }
                }
            }
        }
    }

}
